﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using TunaInterpreter2.Classes;
using System.Diagnostics;
using System.IO;

namespace TunaInterpreter2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string pathToOpenedFile;
        bool SHOW_SPLASH = true;

        public MainWindow()
        {
            InitializeComponent();
            Initialize(); 
        }

        void Initialize()
        {
            drawLineNumbers();
            Paragraph p = editor.Document.Blocks.FirstBlock as Paragraph;
            p.LineHeight = 0.01;
            txtLineNumering.LineHeight = 0.01;
            pathToOpenedFile = "";
            changeDocumentName("New document");

            //-------------------------------------------
            //string content = "int a \n a = 5 \n\n a == 5 ? etiq1 : etiq2";
            //FlowDocument ObjFdoc = new FlowDocument();
            //Paragraph ObjPara1 = new Paragraph();
            //ObjPara1.LineHeight = 0.01;
            //ObjPara1.Inlines.Add(new Run(content));
            //ObjFdoc.Blocks.Add(ObjPara1);
            //editor.Document = ObjFdoc;
            //-------------------------------------------
        }

        void AnalyzeDispatch()
        {
            Thread thread = new Thread(() => Analyze(true));
            thread.Name = "ANALYZE THREAD";
            Console.WriteLine("#### STARTING ANALYZE THREAD");
            thread.Start();
        }

        void RunDispatch()
        {
            Thread thread = new Thread(() => Run());
            thread.Name = "RUN THREAD";
            Console.WriteLine("#### STARTING RUN THREAD");
            thread.Start();
        }

        bool Analyze(bool useStopwatch)
        {
            Stopwatch sw = new Stopwatch();

            if (useStopwatch)
            {
                sw.Start();
            }

            // Samo sprawdzanie bledow bez uruchamiania
            Print(ConsoleMsgType.INFO, "ANALYZING...");
            Tuna t = new Tuna();
            bool result = t.Start(getStringFromRichTextBox(editor), this);

            if (useStopwatch)
            {
                sw.Stop();
                Print(ConsoleMsgType.INFO, "Execution time: " + sw.ElapsedMilliseconds + " ms");
            }

            return result;
        }

        void Run()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            // Sprawdzanie bledow plus uruchomienie
            if (Analyze(false))
            {
                Print(ConsoleMsgType.INFO, "RUNNING...");
                RunScript r = new RunScript();
                r.Start(getStringFromRichTextBox(editor), this);
            }

            sw.Stop();
            Print(ConsoleMsgType.INFO, "Execution time: " + sw.ElapsedMilliseconds + " ms");
        }

        /// <summary>
        /// Wypisuje na ekran wiadomość message. Nowa linia dodawana jest automatycznie
        /// </summary>
        /// <param name="message"> wiadomość do wypisania</param>
        public void Print(ConsoleMsgType type, String message)
        {
            this.Dispatcher.BeginInvoke(
            (Action)delegate()
            {
                if (console.Text == String.Empty)
                {
                    console.Text += type.ToString() + "    " + DateTime.Now.ToLongTimeString() + "    " + message;
                }
                else
                {
                    console.Text += Environment.NewLine;
                    console.Text += type.ToString() + "    " + DateTime.Now.ToLongTimeString() + "    " + message;
                }
            });
        }

        /// <summary>
        /// Czyszczenie konsoli
        /// </summary>
        public void Clean()
        {
            this.Dispatcher.BeginInvoke(
            (Action)delegate()
            {
                console.Text = "";
                consoleScroll.ScrollToTop();
            });
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (SHOW_SPLASH) ShowSplash();
        }

        void ShowSplash()
        {
            this.Hide();
            SplashScreen splash = new SplashScreen();
            splash.ShowDialog();
            this.Show();
        }

        private void menuRun_Click(object sender, RoutedEventArgs e)
        {
            Clean();
            //Print(ConsoleMsgType.INFO, "RUNNING...");
            RunDispatch();
        }

        private void editor_TextChanged(object sender, TextChangedEventArgs e)
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            drawLineNumbers();
            stopWatch.Stop();
            Console.WriteLine("LINE COUNT TIME: " + stopWatch.ElapsedMilliseconds + " ms");
        }

        void drawLineNumbers()
        {
            int count = this.countLines(getStringFromRichTextBox(editor));
            txtLineNumering.Text = "";
            for(int i=1; i<=count ; i++)
            {
                txtLineNumering.Text += i + Environment.NewLine;
            }
        }

        int countLines(string s)
        {
            int count = 0;
            int position = 0;
            while ((position = s.IndexOf('\n', position)) != -1)
            {
                count++;
                position++;
            }
            return count;
        }

        string getStringFromRichTextBox(RichTextBox rtb)
        {
            TextRange textRange = new TextRange(
                // TextPointer to the start of content in the RichTextBox.
                rtb.Document.ContentStart,
                // TextPointer to the end of content in the RichTextBox.
                rtb.Document.ContentEnd
            );

            // The Text property on a TextRange object returns a string 
            // representing the plain text content of the TextRange. 
            return textRange.Text;
        }

        private void menuFileNew_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> File -> New

            FlowDocument ObjFdoc = new FlowDocument();
            Paragraph ObjPara1 = new Paragraph();
            ObjPara1.LineHeight = 0.01;
            ObjPara1.Inlines.Add(new Run(""));
            ObjFdoc.Blocks.Add(ObjPara1);
            editor.Document = ObjFdoc;

            pathToOpenedFile = "";
            changeDocumentName("New document");
        }

        private void menuFileOpen_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> File -> Open
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".tuna"; // Default file extension
            dlg.Filter = "Tuna documents (.tuna)|*.tuna"; // Filter files by extension

            // Show save file dialog box
            Nullable<bool> result = dlg.ShowDialog();

            // Process save file dialog box results
            if (result == true)
            {
                // Save document
                string filename = dlg.FileName;
                string content = String.Empty;

                using (StreamReader reader = new StreamReader(filename))
                {
                    string line;

                    while ((line = reader.ReadLine()) != null)
                    {
                        content += line + Environment.NewLine;
                    }

                    reader.Close();
                }

                FlowDocument ObjFdoc = new FlowDocument();
                Paragraph ObjPara1 = new Paragraph();
                ObjPara1.LineHeight = 0.01;
                ObjPara1.Inlines.Add(new Run(content));
                ObjFdoc.Blocks.Add(ObjPara1);
                editor.Document = ObjFdoc;

                pathToOpenedFile = filename;
                changeDocumentName(filename);
            }
        }

        private void menuFileSave_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> File -> Save
            if(pathToOpenedFile == "")
            {
                //Jak nie ma pliku otwartego to zapisz jako
                menuFileSaveAs_Click(sender, e);
                return;
            }

            using (StreamWriter writer = new StreamWriter(pathToOpenedFile))
            {
                writer.Write(getStringFromRichTextBox(editor));
                writer.Close();
            }

            MessageBox.Show("File saved successfully!", "Saved", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void menuFileSaveAs_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> File -> SaveAs
            // Configure save file dialog box
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName = "TunaCode"; // Default file name
            dlg.DefaultExt = ".tuna"; // Default file extension
            dlg.Filter = "Tuna documents (.tuna)|*.tuna"; // Filter files by extension

            // Show save file dialog box
            Nullable<bool> result = dlg.ShowDialog();

            // Process save file dialog box results
            if (result == true)
            {
                // Save document
                string filename = dlg.FileName;

                using (StreamWriter writer = new StreamWriter(filename))
                {
                    writer.Write(getStringFromRichTextBox(editor));
                    writer.Close();
                }

                MessageBox.Show("File saved successfully!", "Saved", MessageBoxButton.OK, MessageBoxImage.Information);

                pathToOpenedFile = filename;
                changeDocumentName(filename);
            }
        }

        private void menuFileClose_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> File -> Close
            Application.Current.Shutdown();
        }

        private void menuEditSelectAll_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Edit -> Select all
            editor.SelectAll();
        }

        private void menuEditCut_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Edit -> Cut
            if (ApplicationCommands.Cut.CanExecute(null, editor))
            {
                ApplicationCommands.Cut.Execute(null, editor);
            }
        }

        private void menuEditCopy_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Edit -> Copy
            if (ApplicationCommands.Copy.CanExecute(null, editor))
            {
                ApplicationCommands.Copy.Execute(null, editor);
            }
        }

        private void menuEditPaste_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Edit -> Paste
            if (ApplicationCommands.Paste.CanExecute(null, editor))
            {
                ApplicationCommands.Paste.Execute(null, editor);
            }
        }

        private void menuProjectAnalyze_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Project -> Analyze
            Clean();
            
            AnalyzeDispatch();
        }

        private void menuProjectBuildRun_Click(object sender, RoutedEventArgs e)
        {
            //Menu -> Project -> Build and Run
            Clean();
            //Print(ConsoleMsgType.INFO, "RUNNING...");
            RunDispatch();
        }

        private void menuFileAbout_Click(object sender, RoutedEventArgs e)
        {
            About about = new About();
            about.Show();
        }

        void changeDocumentName(String document)
        {
            this.Title = document + " - Tuna Interpreter 2.0";
        }
    }
}
